
/**
 * @file fr_device_canfd.c
 *
 * @author yangcheng
 */

/*********************
 *      INCLUDES
 *********************/
/* Standard includes. */
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

#include "fr30xx.h"
#include "fr_device_canfd.h"
#include "FreeRTOS.h"


/*********************
 *      DEFINES
 *********************/

#define CANFD_DEBUG(fmt,arg...)   printf("[CAN]"fmt,##arg)


/**********************
 *      TYPEDEFS
 **********************/


/**********************
 *  STATIC PROTOTYPES
 **********************/


/**********************
 *  STATIC VARIABLES
 **********************/
static CAN_HandleTypeDef CAN3_Handle;
static uint32_t *Can3Buffer;
static struct_CANRxHeaderDef_t CANRxHeader;
static struct_CANTxHeaderDef_t CANTxHeader;
static uint8_t RxBuffer[256];


/**********************
 *  VARIABLES
 **********************/


/**********************
 *      MACROS
 **********************/


/**********************
 *   EXTERN FUNCTIONS
 **********************/


/**********************
 *   FUNCTIONS
 **********************/
static void RxFIFO0_New_Message_handle(CAN_HandleTypeDef *hcan)
{
    printf("\r\n");

    if (can_get_rxfifo0_fill_level(hcan))
    {
        can_get_rxfifo0_message(hcan, &CANRxHeader, RxBuffer);
        if (CANRxHeader.IdType == CAN_ID_STANDARD)
            printf("Standard ID: %08X, ", CANRxHeader.Identifier);
        else 
            printf("Extended ID: %08X, ", CANRxHeader.Identifier);

#if 0
        CANFD_DEBUG("Timestamp0: %04X, ", CANRxHeader.Timestamp);

        if (CANRxHeader.FormatMode == CAN_CLASSICAL_FRAME)
            printf("CAN_Classical_Frame, ");
        else
            printf("CAN_FD_Frame, ");
        
        if (CANRxHeader.FormatMode == CAN_FD_FRAME)
        {
            if (CANRxHeader.BitRateSwitch)
                printf("Bit Rate Switch enable, ");
            else
                printf("Bit Rate Switch disable, ");
        }
        
        printf("matching filter element: %d, ", CANRxHeader.FilterMatchIndex);
        
        if (CANRxHeader.IdType == CAN_ID_STANDARD)
            printf("Standard ID: %08X, ", CANRxHeader.Identifier);
        else 
            printf("Extended ID: %08X, ", CANRxHeader.Identifier);

        if (CANRxHeader.FrameType == CAN_DATA_FRAME)
            printf("Data_Frame, ");
        else
            printf("Remote_Frame, ");

        printf("Length: %d, ", CANRxHeader.DLC);
        printf("Data: ");
        for (int i = 0; i < CANRxHeader.DLC; i++)
            printf("%02X,", RxBuffer[i]);
        printf("\r\n");
#endif
    }
}

static void RxFIFO1_New_Message_handle(CAN_HandleTypeDef *hcan)
{
    printf("\r\n");

    if (can_get_rxfifo1_fill_level(hcan))
    {
        can_get_rxfifo1_message(hcan, &CANRxHeader, RxBuffer);
        if (CANRxHeader.IdType == CAN_ID_STANDARD)
            printf("Standard ID: %08X, ", CANRxHeader.Identifier);
        else 
            printf("Extended ID: %08X, ", CANRxHeader.Identifier);

#if 0
        CANFD_DEBUG("Timestamp1: %04X, ", CANRxHeader.Timestamp);

        if (CANRxHeader.FormatMode == CAN_CLASSICAL_FRAME)
            printf("CAN_Classical_Frame, ");
        else
            printf("CAN_FD_Frame, ");
        
        if (CANRxHeader.FormatMode == CAN_FD_FRAME)
        {
            if (CANRxHeader.BitRateSwitch)
                printf("Bit Rate Switch enable, ");
            else
                printf("Bit Rate Switch disable, ");
        }
        
        printf("matching filter element: %d, ", CANRxHeader.FilterMatchIndex);
        
        if (CANRxHeader.IdType == CAN_ID_STANDARD)
            printf("Standard ID: %08X, ", CANRxHeader.Identifier);
        else 
            printf("Extended ID: %08X, ", CANRxHeader.Identifier);

        if (CANRxHeader.FrameType == CAN_DATA_FRAME)
            printf("Data_Frame, ");
        else
            printf("Remote_Frame, ");
        
        printf("Length: %d, ", CANRxHeader.DLC);
        printf("Data: ");
        for (int i = 0; i < CANRxHeader.DLC; i++)
            printf("%02X,", RxBuffer[i]);
        printf("\r\n");
#endif
    }
}

static void Transmission_Completed_handle(CAN_HandleTypeDef *hcan)
{
//    CANFD_DEBUG("Tx index: %d, ", __CAN_GET_TxFIFO_QUEUE_GET_INDEX(hcan->CANx));
    CANFD_DEBUG(".");
}

void can3_line0_irq(void)
{
    can_IRQHandler(&CAN3_Handle);
}


void canfd_init(void)
{
    uint32_t ram_size;
    GPIO_InitTypeDef GPIO_Handle;

    // pvPortMalloc(4352*sizeof(uint32_t));
    Can3Buffer = pvPortMalloc(4352 * sizeof(uint32_t));
    
    __SYSTEM_MCAN0_CLK_ENABLE();

    /* CAN0 IO init */
    /* A10: CAN3_Rx */
    /* A11: CAN3_Tx */
    GPIO_Handle.Pin       = GPIO_PIN_10|GPIO_PIN_11;
    GPIO_Handle.Mode      = GPIO_MODE_AF_PP;
    GPIO_Handle.Pull      = GPIO_PULLUP;
    GPIO_Handle.Alternate = GPIO_FUNCTION_5;
    gpio_init(GPIOA, &GPIO_Handle);

    /* CAN init */
    CAN3_Handle.CANx = CAN3;
    CAN3_Handle.Init.Prescaler     = 2;    // 24M/2=12M, bit rate = 12M/16+5+1+1+1 = 500K
    CAN3_Handle.Init.SyncJumpWidth = 3;
    CAN3_Handle.Init.TimeSeg1      = 16;
    CAN3_Handle.Init.TimeSeg2      = 5;
    CAN3_Handle.Init.DataBit_RateSwitch = CAN_FUNC_ENABLE;
    CAN3_Handle.Init.DataBit_Prescaler = 1;    // 24M/1=24M, data bit rate = 24M/16+5+1+1+1 = 1M
    CAN3_Handle.Init.DataBit_SyncJumpWidth = 3;
    CAN3_Handle.Init.DataBit_TimeSeg1 = 16;
    CAN3_Handle.Init.DataBit_TimeSeg2 = 5;
    can_init(&CAN3_Handle);
    /* CAN Message RAM config */
    CAN3_Handle.RAMConfig.StartAddress = (uint32_t)Can3Buffer;
    CAN3_Handle.RAMConfig.StandardIDFilterNums = 128;
    CAN3_Handle.RAMConfig.ExtendedIDFilterNums = 64;
    CAN3_Handle.RAMConfig.TxFIFOQueueNums       = 32;
    CAN3_Handle.RAMConfig.TxDedicatedBufferNums = 0;
    CAN3_Handle.RAMConfig.RxFIFO0Nums           = 64;
    CAN3_Handle.RAMConfig.RxFIFO1Nums           = 64;
    CAN3_Handle.RAMConfig.DataBufferSize = CAN_DATA_BUFFER_SIZE_64_BYTE;
    ram_size = can_message_ram_init(&CAN3_Handle);
    CANFD_DEBUG("can3 use ram size %d\r\n", ram_size);
    
    struct_FilterCfg_t FilterCfg;
    
    /* ---------------------- standard ID filter ---------------------- */
    /* Range filter from SFID1 to SFID2 (SFID2 ≥ SFID1) */
    // FilterCfg.FilterType  = CAN_FILTER_RANGE_FILTER;
    // FilterCfg.ProcessMode = FILTER_PROCESS_SET_PRIORITY_AND_STORE_IN_RxFIFO0;
    // FilterCfg.FilterID_1 = 0x400;
    // FilterCfg.FilterID_2 = 0x500;
    // can_add_standard_filter(&CAN3_Handle, FilterCfg, 0);
    
    FilterCfg.FilterType  = CAN_FILTER_RANGE_FILTER;
    FilterCfg.ProcessMode = FILTER_PROCESS_SET_PRIORITY_AND_STORE_IN_RxFIFO0;
    FilterCfg.FilterID_1 = 0x100;
    FilterCfg.FilterID_2 = 0x200;
    can_add_standard_filter(&CAN3_Handle, FilterCfg, 0);
    
    /* Single ID filter */
    // FilterCfg.FilterType  = CAN_FILTER_SINGLE_ID_FILTER;
    // FilterCfg.ProcessMode = FILTER_PROCESS_SET_PRIORITY_AND_STORE_IN_RxFIFO0;
    // FilterCfg.FilterID_1 = 0x750;
    // FilterCfg.FilterID_2 = 0x750;
    // can_add_standard_filter(&CAN3_Handle, FilterCfg, 1);

    FilterCfg.FilterType  = CAN_FILTER_SINGLE_ID_FILTER;
    FilterCfg.ProcessMode = FILTER_PROCESS_SET_PRIORITY_AND_STORE_IN_RxFIFO0;
    FilterCfg.FilterID_1 = 0x222;
    FilterCfg.FilterID_2 = 0x222;
    can_add_standard_filter(&CAN3_Handle, FilterCfg, 1);

    /* Dual ID filter   */
    FilterCfg.FilterType  = CAN_FILTER_DUAL_ID_FILTER;
    FilterCfg.ProcessMode = FILTER_PROCESS_SET_PRIORITY_AND_STORE_IN_RxFIFO0;
    FilterCfg.FilterID_1 = 0x333;
    FilterCfg.FilterID_2 = 0x334;
    can_add_standard_filter(&CAN3_Handle, FilterCfg, 2);

    // FilterCfg.FilterType  = CAN_FILTER_DUAL_ID_FILTER;
    // FilterCfg.ProcessMode = FILTER_PROCESS_SET_PRIORITY_AND_STORE_IN_RxFIFO0;
    // FilterCfg.FilterID_1 = 0x110;
    // FilterCfg.FilterID_2 = 0x111;
    // can_add_standard_filter(&CAN3_Handle, FilterCfg, 2);

    /* filter and mask */
#if 0
    FilterCfg.FilterType  = CAN_FILTER_CLASSIC_FILTER;
    FilterCfg.ProcessMode = FILTER_PROCESS_SET_PRIORITY_AND_STORE_IN_RxFIFO0;
    FilterCfg.FilterID_1 = 0xF0;    // filter
    FilterCfg.FilterID_2 = 0xFC;    // mask
    can_add_standard_filter(&CAN3_Handle, FilterCfg, 3);

    /* ---------------------- extended ID filter ---------------------- */
    /* Range filter from SFID1 to SFID2 (SFID2 ≥ SFID1) */
    FilterCfg.FilterType  = CAN_FILTER_RANGE_FILTER;
    FilterCfg.ProcessMode = FILTER_PROCESS_SET_PRIORITY_AND_STORE_IN_RxFIFO1;
    FilterCfg.FilterID_1 = 0x10000;
    FilterCfg.FilterID_2 = 0x20000;
    can_add_extended_filter(&CAN3_Handle, FilterCfg, 0);
#endif
    /* Dual ID filter   */
    FilterCfg.FilterType  = CAN_FILTER_SINGLE_ID_FILTER;
    FilterCfg.ProcessMode = FILTER_PROCESS_SET_PRIORITY_AND_STORE_IN_RxFIFO1;
    FilterCfg.FilterID_1 = 0x44444;
    FilterCfg.FilterID_2 = 0x44444;
    can_add_extended_filter(&CAN3_Handle, FilterCfg, 1);
    
    CAN3_Handle.RxFIFO0_New_Message_Callback = RxFIFO0_New_Message_handle;
    CAN3_Handle.RxFIFO1_New_Message_Callback = RxFIFO1_New_Message_handle;
    CAN3_Handle.Transmission_Completed_Callback = Transmission_Completed_handle;
    
    can_int_select_line(&CAN3_Handle, INT_RxFIFO0_NEW_MESSAGE, CAN_INT_LINE0);
    can_int_select_line(&CAN3_Handle, INT_RxFIFO1_NEW_MESSAGE, CAN_INT_LINE0);
    can_int_select_line(&CAN3_Handle, INT_TRANSMISSION_COMPLETED, CAN_INT_LINE0);
    can_int_enable(&CAN3_Handle, INT_RxFIFO0_NEW_MESSAGE);
    can_int_enable(&CAN3_Handle, INT_RxFIFO1_NEW_MESSAGE);
    can_int_enable(&CAN3_Handle, INT_TRANSMISSION_COMPLETED);

    NVIC_EnableIRQ(CAN3_Line0_IRQn);
}

void canfd_exit(void)
{
    NVIC_DisableIRQ(CAN3_Line0_IRQn);
    __SYSTEM_MCAN3_CLK_DISABLE();
    vPortFree(Can3Buffer);
}

unsigned int get_canfd_id(void)
{
    return CANRxHeader.Identifier;
}

unsigned int get_canfd_value(uint8_t *buf, uint16_t len)
{
    uint32_t size = CANRxHeader.DLC;
    if (size > len) {
        size = len;
    }
    memcpy(buf, RxBuffer, size);
    return size;
}

unsigned int get_canfd_count(void)
{
    return CANRxHeader.DLC;
}

unsigned int get_canfd_mode(void)
{
    return CANRxHeader.FormatMode == CAN_CLASSICAL_FRAME ? 0 : 1;
}

